#include "stdafx.h"
#ifdef LIT_OGRE_SUPPORT

#include "LitEntity.h"
#include <tinyxml.h>
#include <OgreSceneManager.h>

namespace Lit
{
	Entity::Entity( const String &name, const String &mesh, OgreSceneNodePtr parentNode )
		: Movable( MT_ENTITY, name )
		, mBaseMesh( mesh )
		, mBaseParent( parentNode )
	{
		/*String				mName;
		OgreSceneNodePtr		mNode;
		OgreSceneManagerPtr		mMgr;
		Ogre::MovableObject*	mObject;
		MovableDatas			mDatas;
		bool					mCreated;

		MovableType				mType;*/
	}
	Entity::Entity( Ogre::Entity*getEntity, Ogre::SceneManager * mgr, OgreSceneNodePtr parentNode )
		: Movable( MT_ENTITY, getEntity->getName() )
		, mBaseMesh( getEntity->getMesh()->getName() )
		, mBaseParent( parentNode )
	{
		mMgr = mgr;
		mNode = getEntity->getParentSceneNode();
		mObject = getEntity;
		mEntity = getEntity;
		mCreated= true;
	}
	Entity::Entity( const Entity& rk )
		: Movable( rk )
	{
		mBaseMesh=rk.mBaseMesh;
		mBaseParent=rk.mBaseParent;
		mEntity = rk.mEntity;
	}
	Entity::~Entity( )
	{
		destroy();
	}
	
	String Entity::getMeshName( bool include_ext ) const{ 
		if( !mCreated ) return ""; 
		String ret=getMesh()->getName();
		if( include_ext ){
			if( !Ogre::StringUtil::endsWith(ret, ".mesh", false) )
				ret += ".mesh";
		}
		else
		{
			if( Ogre::StringUtil::endsWith(ret, ".mesh", false) )
				ret = Ogre::StringUtil::replaceAll(ret, ".mesh", "");
		}
		return ret;
	}

	Ogre::MeshPtr Entity::getMesh() const{ return ( (mCreated) ? mEntity->getMesh() : Ogre::MeshPtr() ); }
	void Entity::setMaterial( Ogre::MaterialPtr mat ){if( mCreated ) mEntity->setMaterial( mat ); }
	void Entity::setMaterialName( const String &mat ){ if( mCreated ) mEntity->setMaterialName(mat); }
	String Entity::getMaterialName( size_t sub_getEntity )const{ return (mCreated?mEntity->getSubEntity(sub_getEntity)->getMaterial()->getName():""); }
	

	bool Entity::replaceMesh( const String &mesh ){
		String nam = mName;
		mCreated = false;
		Ogre::Entity * newEnt = NULL;
		try{
			if( mEntity )
			{
				mEntity->detachFromParent();
				mMgr->destroyEntity(*mEntity);
				mEntity = NULL;
			}
			newEnt = mMgr->createEntity(nam, mesh);
		}
		catch( ... )
		{
			return false;
		}
		mEntity = newEnt;
		mNode->attachObject( *mEntity );
		mCreated = true;
		return true;
	}
	void Entity::create( OgreSceneManagerPtr mgr ){
		if( isCreated() ) return;
		mMgr = mgr;
		mEntity = mMgr->createEntity( mName, mBaseMesh );
		mNode = (mBaseParent?(*mBaseParent):mMgr->getRootSceneNode())->createChildSceneNode();
		mNode->attachObject( *mEntity );

		mEntity->setCastShadows(true);
		mObject = *mEntity;
		mCreated = true;
	}
	void destroyAttachedObjects( Ogre::SceneNode*n )
	{
		if( !n ) return;
		auto i = n->getAttachedObjectIterator();
		while( i.hasMoreElements() )
		{
			Ogre::MovableObject* o = i.getNext();
			if( o )
				n->getCreator()->destroyMovableObject( o );
		}
	}
	void destroyChildNodes(Ogre::SceneNode*n)
	{
		if( !n ) return;
		Ogre::SceneManager* mgr = n->getCreator();
		auto cit = n->getChildIterator();
		while( cit.hasMoreElements() )
		{
			Ogre::SceneNode *cn = (Ogre::SceneNode*)cit.getNext();
			destroyAttachedObjects( cn );
			destroyChildNodes( cn );
		}
		mgr->destroySceneNode( n );
	}
	void Entity::destroy(){ 
		if( !mCreated ) return;
		destroyChildNodes( *mNode );
		
		if( mEntity ){
			mEntity->detachFromParent();
			mMgr->destroyEntity( *mEntity );
		}
		mCreated = false;
	}
	void Entity::exportAttribs( TiXmlElement * elem )
	{
		if( !mCreated ) return;
		elem->SetAttribute( "Name", mName.c_str() );
		elem->SetAttribute( "Mesh", mBaseMesh.c_str() );
		elem->SetAttribute( "Position", Ogre::StringConverter::toString(getPosition()).c_str() );
		elem->SetAttribute( "Orientation", Ogre::StringConverter::toString(getOrientation()).c_str() );
		elem->SetAttribute( "Scale", Ogre::StringConverter::toString(getScale()).c_str() );
	}
	void Entity::importAttribs( TiXmlElement * elem )
	{
		if( !mCreated ) return;
		
		const char * mesh = elem->Attribute("Mesh");
		const char * pos = elem->Attribute("Position");
		const char * orient = elem->Attribute("Orientation");
		const char * scal = elem->Attribute("Scale");

		if( mesh ) replaceMesh( mesh );
		if( pos ) setPosition( Ogre::StringConverter::parseVector3( pos ) );
		if( orient ) setOrientation( Ogre::StringConverter::parseQuaternion( orient ) );
		if( scal ) setScale( Ogre::StringConverter::parseVector3(scal) );
	}
	OgreEntityPtr Entity::getEntity(){ assert(mEntity); return mEntity;}
	const OgreEntityPtr Entity::operator->() const{return getEntity();}

	OgreEntityPtr Entity::operator->(){ return getEntity(); }
	const OgreEntityPtr Entity::getEntity() const{assert(mEntity); return mEntity;}
};

#endif